/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2007 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#include "commonheaders.h"
#include "m_email.h"

namespace NServices {
namespace NSendRecvEMail {

static HANDLE nhMenuItem	= NULL;
static HANDLE nhExtraIcon	= INVALID_HANDLE_VALUE;

/**
 * name:	DBGetEmail
 * desc:	returns the email address of the contact
 * params:	hContact	- handle to contact to read email from
 *			dbv			- retrieves the email address string
 * return:	0 if email was found, 1 otherwise
 **/
static INT DBGetEmail(HANDLE hContact, DBVARIANT *pdbv)
{
	// ignore owner
	if(hContact != NULL) {
		LPCSTR szProto = DBGetContactBaseProto(hContact);
		if(szProto != NULL && (INT)szProto != CALLSERVICE_NOTFOUND && *szProto != 0) {
			// check for private e-mail addresses
			if(
				!DBGetSettingEx(hContact, USERINFO, szProto, SET_CONTACT_EMAIL, pdbv) ||
				!DBGetSettingEx(hContact, USERINFO, szProto, SET_CONTACT_EMAIL0, pdbv) ||
				!DBGetSettingEx(hContact, USERINFO, szProto, SET_CONTACT_EMAIL1, pdbv) ||
				!DBGetSetting(hContact, USERINFO, "Mye-mail0", pdbv)
			  )
			{
				return ((pdbv->type != DBVT_ASCIIZ) || pdbv->pszVal == NULL || mir_strchr(pdbv->pszVal, '@') == NULL);
			}
			// check for company e-mail addresses
			if(
				!DBGetSettingEx(hContact, USERINFO, szProto, SET_CONTACT_COMPANY_EMAIL, pdbv) ||
				!DBGetSettingEx(hContact, USERINFO, szProto, SET_CONTACT_COMPANY_EMAIL0, pdbv) ||
				!DBGetSettingEx(hContact, USERINFO, szProto, SET_CONTACT_COMPANY_EMAIL1, pdbv) ||
				!DBGetSetting(hContact, USERINFO, "MyCompanye-mail0", pdbv)
			  )
			{
				return ((pdbv->type != DBVT_ASCIIZ) || pdbv->pszVal == NULL || mir_strchr(pdbv->pszVal, '@') == NULL);
			}
		}
	}
	return 1;
}

/**
 * name:	MenuCommand
 * desc:	service function that sends emails
 * params:	wParam	- handle to contact to send an email to
 *			lParam	- not used
 * return:	0 if email was sent, 1 if not
 **/
static INT MenuCommand(WPARAM wParam,LPARAM lParam)
{
	DBVARIANT dbv;
	LPSTR szUrl;
	size_t dwLength;

	try {
		if(
			!DBGetEmail((HANDLE)wParam, &dbv) &&
			((dwLength = mir_strlen(dbv.pszVal)) > 0) && 
			(szUrl = (LPSTR)mir_alloc(dwLength += 8)) != NULL
		  )
		{
			mir_snprintfA(szUrl, dwLength, "mailto:%s", dbv.pszVal);
			mir_free(dbv.pszVal);
			CallService(MS_UTILS_OPENURL, 1, (LPARAM)szUrl);
			mir_free(szUrl);
			return 0;
		}
		MessageBox((HWND)lParam, 
			TranslateT("User has not registered an e-mail address"), 
			TranslateT("Send e-mail"), MB_OK);
	}
	catch(...) {
		MessageBox((HWND)lParam, 
			TranslateT("Memory allocation error!"),
			TranslateT("Error"), MB_OK);
	}
	return 1;
}

/***********************************************************************************************************
 * Event Handler functions
 ***********************************************************************************************************/

static INT OnCListRebuildIcons(WPARAM wParam, LPARAM lParam)
{
	nhExtraIcon = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)NIcoLib::GetIcon(ICO_BTN_EMAIL), 0);
	return 0;
}

/**
 * name:	OnCListApplyIcons
 * desc:	notification handler for clist extra icons to be applied for a contact
 * param:	wParam	- handle to the contact whose extra icon is to apply
 *			lParam	- not used
 **/
static INT OnCListApplyIcons(WPARAM wParam, LPARAM lParam)
{
	DBVARIANT dbv;
	IconExtraColumn iec;

	iec.cbSize = sizeof(IconExtraColumn);
	// to support the ugly shitfuckin' clist_nicer++
	iec.ColumnType = myGlobals.IsCListNicer ? 0 : EXTRA_ICON_EMAIL;
	if(!DBGetEmail((HANDLE)wParam, &dbv)) {
		iec.hImage = nhExtraIcon;
		DBFreeVariant(&dbv);
	}
	else {
		iec.hImage = INVALID_HANDLE_VALUE;
	}
	CallService(MS_CLIST_EXTRA_SET_ICON, wParam, (LPARAM)&iec);
	return 0;
}

/**
 * name:	OnContactSettingChanged
 * desc:	Notification handler for changed contact settings
 * param:	wParam	-	(HANDLE)hContact
 *			lParam	-	(DBCONTACTWRITESETTING*)pdbcws
 * return:	0 if setting was handled or 1 if not
 **/
static INT OnContactSettingChanged(WPARAM wParam, LPARAM lParam)
{
	DBCONTACTWRITESETTING* pdbcws = (DBCONTACTWRITESETTING*)lParam;
	
	if(
		!_strnicmp(pdbcws->szSetting, SET_CONTACT_EMAIL, 6) ||
		!_strnicmp(pdbcws->szSetting, "mye-mail0", 9)
	  )
	{
		OnCListApplyIcons(wParam, 0);
	}
	return 0;
}

/**
 * name:	OnPreBuildMenu
 * desc:	decides whether to show menuitem for sending emails or not
 * params:	wParam	- handle to contact to send an email to
 *			lParam	- not used
 * return:	0
 **/
static INT OnPreBuildMenu(WPARAM wParam, LPARAM lParam)
{
	CLISTMENUITEM mi;
	DBVARIANT dbv = { 0 };
	
	ZeroMemory(&mi,sizeof(mi));
	mi.cbSize = sizeof(mi);
	mi.flags = CMIM_FLAGS;

	if(DBGetEmail((HANDLE)wParam, &dbv)) {
		mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
	}
	CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)nhMenuItem, (LPARAM)&mi);
	if(dbv.pszVal) DBFreeVariant(&dbv);
	return 0;
}

/***********************************************************************************************************
 * public Module Interface functions
 ***********************************************************************************************************/

/**
 * name:	RebuildMenu
 * desc:	enable or disable menuitem
 * params:	not used
 * return:	nothing
 **/
VOID RebuildMenu()
{
	static HANDLE hPrebuildMenuHook = NULL;

	if(!hPrebuildMenuHook) {
		hPrebuildMenuHook = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, OnPreBuildMenu);
	}

	if(!nhMenuItem) {
		CLISTMENUITEM mi;

		// insert contact menuitem
		ZeroMemory(&mi, sizeof(mi));
		mi.cbSize = sizeof(mi);
		mi.position = -2000010000;
		mi.hIcon = NIcoLib::GetIcon(ICO_BTN_EMAIL);
		mi.pszName = "&E-mail";
		mi.pszService = MS_EMAIL_SENDEMAIL;
		nhMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
	}
}

/**
 * name:	ApplyCListIcons
 * desc:	force all icons to be reloaded
 * param:	wParam	- handle to the contact whose extra icon is to apply
 *			lParam	- not used
 **/
VOID ApplyCListIcons()
{
	WPARAM wContact;

	//walk through all the contacts stored in the DB
	for(wContact = CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
		wContact != NULL;
		wContact = CallService(MS_DB_CONTACT_FINDNEXT, wContact, 0))
	{
		OnCListApplyIcons(wContact, 0);
	}
}

/**
 * name:	EnableExtraIcons
 * desc:	reload the module
 * params:	bEnable	- determines whether icons are enabled or not
 * return:	0
 **/
VOID EnableExtraIcons(BOOLEAN bEnable, BOOLEAN bUpdateDB) 
{
	static HANDLE	hChangedHook = 0,
					hApplyIconHook = 0,
					hRebuildIconsHook = 0;

	if(!myGlobals.HaveCListExtraIcons)
		return;

	if(bUpdateDB)
		DBWriteContactSettingByte(NULL, MODNAME, SET_CLIST_EXTRAICON_EMAIL, bEnable);

	if(bEnable) {
		// hook events
		if(hChangedHook == NULL) hChangedHook = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, OnContactSettingChanged);
		if(hApplyIconHook == NULL) hApplyIconHook = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, OnCListApplyIcons);
		if(hRebuildIconsHook == NULL) hRebuildIconsHook = HookEvent(ME_CLIST_EXTRA_LIST_REBUILD, OnCListRebuildIcons);

		OnCListRebuildIcons(0, 0);
	}
	else {
		UnhookEvent(hChangedHook); hChangedHook = NULL;
		UnhookEvent(hApplyIconHook); hApplyIconHook = NULL;
		UnhookEvent(hRebuildIconsHook); hRebuildIconsHook = NULL;
	}
	ApplyCListIcons();
}

/**
 * name:	OnModulesLoaded
 * desc:	initialize stuff, which require all standard modules to bee loaded
 * params:	none
 * return:	0
 **/
VOID OnModulesLoaded()
{
	EnableExtraIcons(DBGetByte(SET_CLIST_EXTRAICON_EMAIL, DEFVAL_CLIST_EXTRAICON_EMAIL), FALSE);
}

/**
 * name:	LoadModule
 * desc:	initiate the module
 * params:	none
 * return:	0
 **/
VOID LoadModule()
{
	// prevent default email module from loading
	LPINT disableDefaultModule = (LPINT)CallService(MS_PLUGINS_GETDISABLEDEFAULTARRAY, 0, 0);
	disableDefaultModule[DEFMOD_SREMAIL] = TRUE;
		
	// create own email send command
	DestroyServiceFunction((HANDLE)hashSetting(MS_EMAIL_SENDEMAIL));
	CreateServiceFunction(MS_EMAIL_SENDEMAIL, MenuCommand);
}

} // namespace NSendRecvEMail
} // namespace NServices
